package ar.unc.famaf.pln.giveselector.utils;

import java.sql.SQLException;
import java.util.*;

import give.comm.*;
import give.comm.log.StderrLogger;
import give.formula.*;
import give.mapreplay.GameEvent;
import give.matchmaker.MatchmakerConfiguration;
import give.matchmaker.db.DatabaseInterface;
import give.world.*;

/**
 * A GIVEConnector contains useful methods to access the GIVE databases.
 * @author Alexandre Denis
 */
public class GIVEConnector
{
	private final DatabaseInterface db;
	private final MatchmakerConfiguration config;


	/**
	 * Creates a new GiveConnecter with given matchmaker configuration file.
	 * @param matchmakerFile
	 */
	public GIVEConnector(String matchmakerFile)
	{
		config = new MatchmakerConfiguration(new StderrLogger("gle", false));
		config.readFromFile(matchmakerFile);
		db = config.getDb();
		if (db.getDatabaseConnection()==null)
		{
			System.err.println("Unable to connect to the database. Check if your sql server is running and the configuration in file "+matchmakerFile);
			System.exit(-1);
		}
	}


	/**
	 * Returns all game ids based on given world.
	 */
	public Set<Integer> getGameIdsByWorld(World world)
	{
		Set<Integer> ret = new HashSet<Integer>();
		for(Integer gameId : getGameIds())
		{
			System.out.println(getWorld(gameId).getName() + " = " + world.getName());
			if (getWorld(gameId).getName().equals(world.getName()))
				ret.add(gameId);
		}
		return ret;
	}

	/**
	 * Returns the server name of a given game id
	 */
	public String getServerName(Integer gameId)
	{
		try
		{
			return db.getGameData(gameId).serverName;
		}
		catch (SQLException e)
		{
			e.printStackTrace();
			System.exit(-1);
		}
		return null;
	}
	
	/**
	 * Returns a list with all the valid games from the given nlg server name. 
	 */
	public List<Integer> getGameIdsFromServer(String serverName)
	{
		List<Integer> result = new ArrayList<Integer>();
		for (Integer id : getGameIds())
		{
			if (getServerName(id).toLowerCase().equals(serverName.toLowerCase()))
			{
				result.add(id);
			}
		}
		return result;
	}

	/**
	 * Returns the World corresponding to the given game id.
	 * @param gameId
	 * @return
	 * @throws SQLException
	 */
	public World getWorld(int gameId)
	{
		try
		{
			String worldName = db.getGameData(gameId).worldName;
			World world = config.getWorldManager().getWorldForName(worldName);
			if (world == null)
			{
				System.err
						.println("Error: Unable to find world " + worldName + " in the matchmaker configuration file");
				System.exit(-1);
			}
			else return world;
		}
		catch (SQLException e)
		{
			e.printStackTrace();
			System.exit(-1);
		}
		return null;
	}


	/**
	 * Returns the list of all valid games ids.
	 */
	public List<Integer> getGameIds()
	{
		try
		{
			return db.getAllValidGameIds();
		}
		catch (SQLException e)
		{
			e.printStackTrace();
			return new ArrayList<Integer>();
		}
	}


	/**
	 * Displays the given list of events.
	 * @param events
	 */
	public void displayEvents(List<GameEvent> events)
	{
		for(GameEvent event : events)
			displayEvent(event);
	}


	/**
	 * Displays the given event.
	 * @param event
	 */
	public void displayEvent(GameEvent event)
	{
		Message message = event.message;
		if (message instanceof ActionMessage)
		{
			Atom action = ((ActionMessage) message).getHeader();
			System.out.println("\taction: " + action.getArgumentAsString(0));
		}
		else if (message instanceof TextMessage)
		{
			String text = ((TextMessage) message).getText();
			System.out.println(text);
		}
	}


	/**
	 * Returns the list of game events for the given game sorted by timestamps.
	 */
	public List<GameEvent> getGameEvents(int gameId)
	{
		try
		{
			List<GameEvent> ret = new ArrayList<GameEvent>();
			List<Date> timestamps = new ArrayList<Date>();
			List<String> messages = new ArrayList<String>();
			db.retrieveGameEvents(gameId, timestamps, messages);
			for(int i = 0; i < timestamps.size(); i++)
				ret.add(new GameEvent(timestamps.get(i), Message.parse(messages.get(i))));
			return ret;
		}
		catch (SQLException e)
		{
			e.printStackTrace();
			return new ArrayList<GameEvent>();
		}
	}
}
